package me.zhengjie.modules.hanzi.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.hanzi.domain.Category;
import me.zhengjie.modules.hanzi.domain.HanziCharacter;
import me.zhengjie.modules.hanzi.domain.UserProgress;
import me.zhengjie.modules.hanzi.mapper.CategoryMapper;
import me.zhengjie.modules.hanzi.mapper.CharacterMapper;
import me.zhengjie.modules.hanzi.mapper.UserProgressMapper;
import me.zhengjie.utils.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@RequiredArgsConstructor
public class HanziService {
    private final CharacterMapper characterMapper;
    private final CategoryMapper categoryMapper;
    private final UserProgressMapper userProgressMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final RestTemplate restTemplate;

    public Page<HanziCharacter> getCharacters(int page, int limit, String level) {
        QueryWrapper<HanziCharacter> wrapper = new QueryWrapper<>();
        if (level != null) {
            wrapper.eq("level", level);
        }
        wrapper.orderByAsc("stroke_count");
        return characterMapper.selectPage(new Page<>(page, limit), wrapper);
    }

    public HanziCharacter getCharacter(String character) {
        return characterMapper.selectOne(new QueryWrapper<HanziCharacter>()
            .lambda()
            .eq(HanziCharacter::getCharacter, character));
    }

    public List<Category> getCategories() {
        List<Category> categories = categoryMapper.selectList(null);
        for (Category category : categories) {
            int count = characterMapper.selectCount(
                new QueryWrapper<HanziCharacter>()
                    .eq("category_id", category.getCategoryId())
            ).intValue();
            category.setCount(count);
        }
        return categories;
    }

    public Page<HanziCharacter> getCategoryCharacters(String categoryId, int page, int limit) {
        QueryWrapper<HanziCharacter> wrapper = new QueryWrapper<HanziCharacter>().isNotNull("pinyin").isNotNull("level").isNotNull("stroke_count").orderByAsc("stroke_count").orderByAsc("level");
        wrapper = "1".equals(categoryId) ? wrapper : wrapper.eq("category_id", categoryId);
        return characterMapper.selectPage(new Page<>(page, limit), wrapper);
    }

    public HanziCharacter getDailyCharacter() {
        LocalDate today = LocalDate.now();
        int seed = today.getYear() * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth();
        
        return characterMapper.selectOne(new QueryWrapper<HanziCharacter>()
            .lambda()
            .select(HanziCharacter::getCharacter, 
                   HanziCharacter::getPinyin, 
                   HanziCharacter::getMeaning)
            .last("ORDER BY RAND(" + seed + ") LIMIT 1"));
    }

    public Map<String, Object> getUserProgress(Long userId) {
        Map<String, Object> result = new HashMap<>();

        // 获取学习统计
        QueryWrapper<UserProgress> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        long learnedCount = userProgressMapper.selectCount(wrapper);

        result.put("learnedCount", learnedCount);
        result.put("totalCount", characterMapper.selectCount(null));

        // 获取最近学习的汉字
        wrapper.orderByDesc("learn_time");
        wrapper.last("LIMIT 10");
        List<UserProgress> recentLearned = userProgressMapper.selectList(wrapper);

        result.put("recentLearned", recentLearned);
        return result;
    }

    public void updateProgress(Long userId, String character, String status) {
        UserProgress progress = new UserProgress();
        progress.setUserId(userId);
        progress.setCharacter(character);
        progress.setStatus(status);
        progress.setLearnTime(LocalDateTime.now());
        userProgressMapper.insert(progress);
    }

    public String getCharacterImg(String character) {
        String cacheKey = "char_img:" + character;
        String cachedData = stringRedisTemplate.opsForValue().get(cacheKey);

        try {
            String url = String.format("https://hanyuapp.baidu.com/dictapp/word/detail_getworddetail?wd=%s&client=pc&lesson_from=xiaodu&smp_names=wordNewData1", character);
            Map forObject = restTemplate.getForObject(url, Map.class);

            if (forObject != null && forObject.containsKey("data")) {
                Object data = forObject.get("data");
                if (Objects.nonNull(data)) {
                    Map<String, Object> resultData = StringUtils.convertObjectToMap(data);
                    Map detaildetailmap = (Map) resultData.get("detail");
                    String img = (String) detaildetailmap.get("img");
                    // 设置缓存，过期时间1天
                    stringRedisTemplate.opsForValue().set(cacheKey, img, 24, TimeUnit.HOURS);
                    return img;
                }
            }

            throw new RuntimeException("百度汉语API返回数据不包含汉字 " + character + " 的笔顺信息");

        } catch (RestClientException e) {
            log.error("获取汉字 {} 的笔顺数据时发生网络错误: {}", character, e.getMessage());
            throw new RuntimeException("获取汉字 " + character + " 的笔顺数据时发生网络错误: " + e.getMessage(), e);
        } catch (Exception e) {
            log.error("获取汉字 {} 的笔顺数据时发生未知错误: {}", character, e.getMessage(), e);
            throw new RuntimeException("获取汉字 " + character + " 的笔顺数据时发生未知错误: " + e.getMessage(), e);
        }
    }

    public List<HanziCharacter> getUserLearningCharacters(String username) {
        return null;
    }
}